let W = null
class Watcher {
    constructor(data, key) {
        this.data = data
        this.key = key
        // 获取值的时候,数据劫持中会收集我这个watcher实例,所以我要把watcher实例放在全局变量W上
        W = this

        this.get()
        // 当依赖被收集以后,请把W还出去,否则下次不用watcher获取值的时候也会把我这个watcher收集进去
        W = null

    }

    get() {
        return this.data[this.key]
    }

    update() {
        console.log(`${this.key}数据更新，重新获取${this.get()},重新渲染视图`);
    }
}

class Dep {
    constructor() {
        //存放所有依赖
        this.subs = []
    }

    addDeppend(watcher) {
        this.subs.push(watcher)
    }

    notify() {
        this.subs.forEach(watcher => {
            watcher.update()
        })
    }
}

function defineReactive(data, key, value) {
    observe(value)

    const dep = new Dep()

    Object.defineProperty(data, key, {
        get() {
            console.log('数据劫持的getter中获取数据',key);

            if (W) {
                dep.addDeppend(W)
            }

            return value

        },
        set(newVal) {
            console.log('数据劫持的setter中设置数据',key);
            value = newVal

            dep.notify()
        }
    })
}

//Observer类就是发布-订阅模型中的发布者
class Observer {
    constructor(_data) {
        this._data = _data

        if (Array.isArray(this._data)) {
            this.observerArray(this._data)
        } else {
            this.walk(this._data)
        }
    }
    // 数组，先遍历，查看数组内部是否有对象，是否需要进行深层次的数据响应式处理
    observerArray(_data) {
        _data.forEach(item => {
            return observe(item)
        })
    }
    // 对象，直接进行响应式处理
    walk(_data) {
        for (let key of Object.keys(_data)) {
            defineReactive(_data, key, _data[key])
        }
    }

}

function observe(_data) {
    // 基本数据类型直接不做任何处理
    if (typeof _data !== 'object' || _data === null) return

    new Observer(_data)
}

function Vue(options) {
    // 把数据放在_data上
    this._data = options.data

    for (let key of Object.keys(this._data)) {
        Object.defineProperty(this, key, {
            get() {
                return this._data[key]
            },
            set(newVal) {
                this._data[key] = newVal
            }
        })
    }

    // 判断需要被响应式处理的数据类型，
    // 基本类型，不进行响应式处理
    observe(this._data)
}

const vm = new Vue({
    data: {
        count: 0,
        person: {
            name: 'laowang',
            age: 18
        }
    }
})


function huoqu() {
    // console.log(vm, 'count');
    new Watcher(vm, 'count')
}

function shezhi() {
    vm.count =2
}
huoqu()
shezhi()